package com.sun.framework.service.impl;

import com.sun.common.pojo.SsqQuery;
import com.sun.common.pojo.SsqVo;
import com.sun.framework.service.SsqDataService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;

import static com.sun.common.constants.Constant.EQUAL;
import static com.sun.common.utils.SsqDataUtil.*;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SsqDataServiceImpl implements SsqDataService {

    private final List<String> ssqData;
    private final List<List<Integer>> allRedCombinations;

    // 中奖数据列表
    private final List<SsqVo> winningDataList = new ArrayList<>();
    // 中奖号码列表
    private final Set<String> winningNumberSet = new HashSet<>();
    // 所有组合数据
    private final List<SsqVo> allCombinationsList = new ArrayList<>();

    @PostConstruct
    private void init() {
        initWinningData(ssqData);
        initAllCombinations();
    }

    /**
     * 初始化中奖数据
     * @param ssqData 中奖数据列表
     */
    private void initWinningData(List<String> ssqData) {
        winningNumberSet.clear();
        winningDataList.clear();

        for (String line : ssqData) {
            String[] split = line.split("\\|");
            String[] ssqSplit = split[2].split("\\+");
            String redBall = ssqSplit[0];
            String blueBall = ssqSplit[1];
            winningNumberSet.add(redBall);

            SsqVo ssq = new SsqVo();
            ssq.setDate(split[0]);
            ssq.setIssue(split[1]);
            ssq.setCombination(redBall);
            ssq.setBlueBall(blueBall);
            ssq.setAcValue(split[5].split(EQUAL)[1].trim());
            ssq.setSerialNo(split[6].split(EQUAL)[1].trim());
            ssq.setSumValue(split[7].split(EQUAL)[1].trim());
            ssq.setOddEvenRatio(split[8].split(EQUAL)[1].trim());
            ssq.setDistribution(split[9].split(EQUAL)[1].trim());
            ssq.setBonus(split[3]);
            winningDataList.add(ssq);
        }
    }

    /**
     * 初始化所有组合数据（红球为全量组合+蓝球为随机数字）
     */
    private void initAllCombinations() {
        for (List<Integer> ssq : allRedCombinations) {
            StringBuilder combination = new StringBuilder();
            for (int i = 0; i < ssq.size(); i++) {
                combination.append(fillZero(ssq.get(i)));
                if(i != ssq.size() - 1) {
                    combination.append(",");
                }
            }
            if(!winningNumberSet.contains(combination.toString())) {
                allCombinationsList.add(getSsqFilterVo(ssq, combination.toString()));
            }
        }
    }

    @Override
    public List<SsqVo> findWinningDataByCondition(SsqQuery ssqQuery) {
        return filterData(ssqQuery, winningDataList);
    }

    @Override
    public void updateLatestWinningData() {
        // 查询最新数据
        List<String> latestDataList = queryLatestData(getStartIssue(), getLatestIssue());

        // 分析最新数据
        List<String> analysisDataList = analysisLatestData(latestDataList);

        // 写出最新数据
        writeLatestData(analysisDataList);

        // 更新到缓存
        initWinningData(analysisDataList);
    }

    /**
     * 过滤数据
     * @param ssqQuery 查询条件
     * @param ssqList 已开奖组合
     * @return 过滤后的数据列表
     */
    private static List<SsqVo> filterData(SsqQuery ssqQuery, List<SsqVo> ssqList) {
        List<SsqVo> dateList = filterDataByCondition(ssqQuery.getDate(), "date", ssqList);
        List<SsqVo> acList = filterDataByCondition(ssqQuery.getAcValue(), "ac", dateList);
        List<SsqVo> serialNoList = filterDataByCondition(ssqQuery.getSerialNo(), "serialNo", acList);
        List<SsqVo> sumValueList = filterDataByCondition(ssqQuery.getSumValue(), "sum", serialNoList);
        List<SsqVo> oddEvenRatioList = filterDataByCondition(ssqQuery.getOddEvenRatio(), "oddEvenRatio", sumValueList);
        List<SsqVo> distributionList = filterDataByCondition(ssqQuery.getDistribution(), "distribution", oddEvenRatioList);
        List<SsqVo> includeNumberList = includeNumber(ssqQuery, distributionList);
        return excludeNumber(ssqQuery, includeNumberList);
    }

    /**
     * 根据条件过滤数据
     * @param condition 条件字段
     * @param type 条件类型
     * @param ssqList 已开奖组合
     * @return 过滤后的数据列表
     */
    private static List<SsqVo> filterDataByCondition(String condition, String type, List<SsqVo> ssqList) {
        if(StringUtils.isBlank(condition)) {
            return ssqList;
        }
        List<SsqVo> filterList = new ArrayList<>();
        for (SsqVo ssq : ssqList) {
            String conditionValue = getConditionValueByType(type, ssq);
            if(StringUtils.equalsAnyIgnoreCase(condition, conditionValue)) {
                filterList.add(ssq);
            }
        }
        return filterList;
    }

    /**
     * 根据类型获取字段值
     * @param type 类型
     * @param ssq 已开奖组合
     * @return 字段值
     */
    private static String getConditionValueByType(String type, SsqVo ssq) {
        switch (type) {
            case "date":
                return ssq.getDate();
            case "ac":
                return ssq.getAcValue();
            case "serialNo":
                return ssq.getSerialNo();
            case "sum":
                return ssq.getSumValue();
            case "oddEvenRatio":
                return ssq.getOddEvenRatio();
            case "distribution":
                return ssq.getDistribution();
            default:
                return "";
        }
    }

    @Override
    public List<SsqVo> queryCombinationByCondition(SsqQuery ssqQuery) {
        return filterData(ssqQuery, subSsqList(ssqQuery));
    }

    /**
     * 截取数据
     * @param ssqQuery 查询条件
     * @return 截取数据列表
     */
    private List<SsqVo> subSsqList(SsqQuery ssqQuery) {
        String randomCount = ssqQuery.getRandomCount();
        if(!StringUtils.equalsIgnoreCase("ALL", randomCount)) {
            return allCombinationsList.subList(0, Integer.parseInt(randomCount));
        }
        return allCombinationsList;
    }

    /**
     * 包含号码
     * @param ssqQuery 查询条件
     * @param filterSsqList 需要过滤的组合列表
     * @return 包含号码的组合列表
     */
    private static List<SsqVo> includeNumber(SsqQuery ssqQuery, List<SsqVo> filterSsqList) {
        String includeNumber = ssqQuery.getIncludeNumber();
        if(StringUtils.isNotBlank(includeNumber)) {
            List<SsqVo> fixedNumberList = new ArrayList<>();
            for (SsqVo ssq : filterSsqList) {
                if(checkIfAllExist(ssq.getCombination(), includeNumber)) {
                    fixedNumberList.add(ssq);
                }
            }
            return fixedNumberList;
        }
        return filterSsqList;
    }

    /**
     * 号码是否存在
     * @param combination 双色球列表
     * @param includeNumber 包含号码
     * @return 存在：true 不存在：false
     */
    public static boolean checkIfAllExist(String combination, String includeNumber) {
        String[] numbers = includeNumber.split(",");
        for (String number : numbers) {
            number = !StringUtils.startsWith(number, "0")
                    && Integer.parseInt(number) < 10 ? "0" + number : number;
            if (!combination.contains(number)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 排除号码
     * @param ssqQuery 查询条件
     * @param includeNumberList 需要过滤的组合列表
     * @return 不包含号码的组合列表
     */
    private static List<SsqVo> excludeNumber(SsqQuery ssqQuery, List<SsqVo> includeNumberList) {
        String excludeNumber = ssqQuery.getExcludeNumber();
        if(StringUtils.isNotBlank(excludeNumber)) {
            List<SsqVo> excludeNumberList = new ArrayList<>();
            for (SsqVo ssq : includeNumberList) {
                if(checkIfAllNotExist(ssq.getCombination(), excludeNumber)) {
                    excludeNumberList.add(ssq);
                }
            }
            return excludeNumberList;
        }
        return includeNumberList;
    }

    /**
     * 号码都不存在
     * @param combination 双色球列表
     * @param includeNumber 排除号码
     * @return 都不存在：true 存在：false
     */
    public static boolean checkIfAllNotExist(String combination, String includeNumber) {
        String[] numbers = includeNumber.split(",");
        for (String number : numbers) {
            number = !StringUtils.startsWith(number, "0")
                    && Integer.parseInt(number) < 10 ? "0" + number : number;
            if (combination.contains(number)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取页面显示对象
     * @param ssq 双色球组合
     * @param combination 用逗号隔开的双色球组合
     * @return 显示对象
     */
    private SsqVo getSsqFilterVo(List<Integer> ssq, String combination) {
        // AC
        int acValue = calcACValue(ssq);
        // 连号数
        int serialNo = calcSerialNumber(ssq);
        // 和值
        int sum = calcSum(ssq);
        // 奇偶比
        String oddEven = calcOddEven(ssq);
        // 三区分布
        String distribution = calcDistribution(ssq);

        SsqVo ssqVo = new SsqVo();
        ssqVo.setCombination(combination);
        ssqVo.setSerialNo(String.valueOf(serialNo));
        ssqVo.setSumValue(String.valueOf(sum));
        ssqVo.setOddEvenRatio(oddEven);
        ssqVo.setDistribution(distribution);
        ssqVo.setAcValue(String.valueOf(acValue));
        int blueBall = new Random().nextInt(16) + 1;
        ssqVo.setBlueBall(fillZero(blueBall));
        return ssqVo;
    }

    /**
     * 小于10的数字，前面加0。
     * @param num 数字
     * @return 数字字符
     */
    private static String fillZero(int num) {
        String numStr;
        if(num < 10) {
            numStr = "0" + num;
        } else {
            numStr = String.valueOf(num);
        }
        return numStr;
    }

}
